Add AuthenticationComponent::replaceIdentity()#788
Conversation
Swaps the in-request identity attribute without going through clearIdentity()/persistIdentity(). Useful for cache-warming the active identity (eager-loaded associations, computed flags) without ending impersonation or rotating the session. Adds AuthenticationServiceInterface::buildIdentity() so the component can build an identity object using the configured identityClass via the public service API.
|
The fact that Your proposed solution of Maybe we need an option for Another related issue with using If you use |
… option - AuthenticationServiceInterface: revert added buildIdentity() method declaration and replace with a @method docblock annotation. Adding a method to the interface is BC-breaking for any third-party implementer and cannot ship in 4.x or 4.next. - AuthenticationComponent::setIdentity() gains a $preserveImpersonation flag. When true, the new identity is persisted into the session as usual, but an active impersonation session is left intact (as is the successfully resolved authenticator). - AuthenticationService::clearIdentity() gains an optional third $stopImpersonation parameter that backs the new behavior. The interface signature is unchanged, so external implementers remain compatible. - Adds tests covering both the preserveImpersonation path and the default path that still ends impersonation.
|
Pushed an update that addresses both points. On the interface BC break (per @LordSimal): On your "needs to persist for subsequent requests" point: So I went with option A: a new flag on $this->Authentication->setIdentity($reloaded, preserveImpersonation: true);Implementation: The two methods now have distinct intents:
New tests cover both the impersonation-preserving path and a regression test confirming the default On the Why I deferred it There are three possible fixes and none are 1-line:
$this->Authentication->setIdentity($reloaded);
if ($this->request->getAttribute('authorization')) {
$identity = new IdentityDecorator(
$this->request->getAttribute('authorization'),
$this->request->getAttribute('identity'),
);
$this->setRequest($this->request->withAttribute('identity', $identity));
}
|
…tion - Adds a 'Replacing the current identity' section to authentication-component.md covering setIdentity(), replaceIdentity() and the preserveImpersonation flag with usage examples. - Adds a third 'Limitations' bullet to impersonation.md explaining that setIdentity()/clearIdentity() end impersonation by default and pointing at the two new APIs as the supported workarounds.
Summary
Adds
AuthenticationComponent::replaceIdentity()for swapping the in-request identity attribute without going throughclearIdentity()/persistIdentity().Motivation
A common pattern in apps is to enrich the active user with eager-loaded associations or computed flags in
AppController::beforeFilter(). Doing this withsetIdentity()has a surprising side effect:setIdentity()callsclearIdentity()first, and the service'sclearIdentity()actively callsstopImpersonating()on impersonation-aware authenticators (AuthenticationService.phplines 192-200). So a pattern likesilently ends impersonation on every request where the association was missing.
replaceIdentity()solves this by writing only to the request attribute - no session writes, noclearIdentitychain, no impersonation interaction. It mirrors whatwithAttribute('identity', new Identity($data))does, but routes through the service so the configuredidentityClassis honored.Changes
AuthenticationComponent::replaceIdentity(ArrayAccess|array $identity)- new methodAuthenticationServiceInterface::buildIdentity()- lifted to the interface so the component can call it without a concrete-type cast (the method already existed onAuthenticationService)